package org.elcom.sources;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Scanner;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;

public class FTPDownload {

	private static String dir = "";
	private static String dirSaveName = "";
	private static String newDirPath = "";
	static boolean result = false;
	
	//download from remote directory
	public static void downloadDirectory(FTPClient ftpClient, String parentDir,
			String currentDir, String saveDir) throws Exception {
			
		String dirToList = parentDir;
		if (!currentDir.equals("")) {
			dirToList += "/" + currentDir;
		}

		FTPFile[] subFiles = ftpClient.listFiles(dirToList);

		if (subFiles != null && subFiles.length > 0) {
			for (FTPFile aFile : subFiles) {	//scan all file and folder
				String currentFileName = aFile.getName();
				 if (currentFileName.equals(".") || currentFileName.equals("..")) {
		                // skip parent directory and the directory itself
		                continue;
		            }
		            String filePath = parentDir + "/" + currentDir + "/"
		                    + currentFileName;
		            if (currentDir.equals("")) {
		                filePath = parentDir + "/" + currentFileName;
		            }
		            
				if (aFile.isDirectory() == true) { 
					// create the directory in saveDir
					/*File newDir = new File(newDirPath);
					if(newDir.exists() == true){
						System.out.println("Folder " + newDirPath + " is exist");
					}
					else {
						boolean created = newDir.mkdirs();
						if (created) {
							System.out.println("Created the directory: " + newDirPath);
						}
						else {
							System.out.println("Failed to create the directory: " + newDirPath);
						}
					}*/
					
					// download the sub directory
					downloadDirectory(ftpClient, dirToList, currentFileName, saveDir);					
				}
				else {
					// check exists
					try {
						String nameFile;
						boolean isDownloaded = false;
						File fi = new File(Config.downloadedFileDir);
						if(!fi.exists()){
							fi.createNewFile();
						}
						// check file has downloaded (on download.txt)
						FileInputStream file = new FileInputStream(Config.downloadedFileDir);
						Scanner input = new Scanner(file);
						
						while (input.hasNextLine()) {
							nameFile = input.nextLine();
							if(filePath.equals(nameFile) == true){
//								System.out.println("   File " + nameFile + " is downloaded");
								isDownloaded = true;
							}
						}
						
						if(isDownloaded == false){
							// download the file
							createNameOfDir();
							File dirDes = new File(dirSaveName);			
//							createDirByName(saveDir);
							
							if (dirDes.exists()) {
								downloadFile(ftpClient, filePath, saveDir);	
							} else {
								createDirByName(Config.saveDirPath);
								downloadFile(ftpClient, filePath, saveDir);
							}
							
//							newDirPath = saveDir + File.separator + dir + currentFileName;
//				            if (currentDir.equals("")) {
//				                newDirPath = saveDir + File.separator + currentFileName;
//				            }
							
						}
						
					} catch (FileNotFoundException e) {
						e.printStackTrace();

						int time = FTPClientDemo.time - 1000;
						result = redownload(ftpClient, filePath, newDirPath, time);
						while(!result){
							time += 1000;
							result = redownload(ftpClient, filePath, newDirPath, time);
						}
						
					} catch (IOException e) {
//						System.out.println("Loi doc file downloaded.txt");
					} catch (Exception e) {
//						e.printStackTrace();
						System.out.println("error");
					}
				}
			}
		}
	}

	public static void downloadFile(FTPClient ftpClient, String filePath, String newDirPath) throws Exception{
		
		File nameFilePath = new File(filePath);
		newDirPath = newDirPath + File.separator + nameFilePath.getName(); 
		
		boolean success = downloadSingleFile(ftpClient, filePath, newDirPath);
		
//		FTPFile fi = ftpClient.mlistFile(filePath);
//		long size = fi.getSize();
		
		if (success) {
			while(!MD5.checkMD5("ftp://" + Config.ip + filePath, newDirPath)){
				downloadSingleFile(ftpClient, filePath,	newDirPath);
			}
			String destinationPath = dirSaveName + newDirPath.substring(Config.templateDir.length() + 1);
//			System.out.println("Des: " + destinationPath);
			if(moveToDesDir(newDirPath, destinationPath)){
				System.out.println("\tDownloaded the file: " + filePath);
				
				//create log file downloaded
				File newFile = new File(Config.downloadedFileDir);
				FileOutputStream fos = new FileOutputStream(newFile, true);
				PrintWriter print = new PrintWriter(fos);
				print.println(filePath);
				print.close();					

			}
		}
		else {
			Connect.reconnectToServer(Config.waitingTime);
		}
	}
	//move file from template folder to destination folder
	private static boolean moveToDesDir(String srcFilePath, String desFilePath) {
		
		File srcFile = new File(srcFilePath);
		File desFile = new File(desFilePath);
		Path srcPath = srcFile.toPath();
		Path desPath = desFile.toPath();
		
		try {
			Files.move(srcPath, desPath, StandardCopyOption.REPLACE_EXISTING);
			return true;
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("Error tranfering file");
			return false;
		}
	}

	//download file from server
	public static boolean downloadSingleFile(FTPClient ftpClient,
			String remoteFilePath, String savePath) throws Exception {
		File downloadFile = new File(savePath);
		OutputStream outputStream = new BufferedOutputStream(
				new FileOutputStream(downloadFile));
		try {
			//downloading file
				ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
				ftpClient.retrieveFile(remoteFilePath, outputStream);
				return true;
		} catch (FileNotFoundException e) {
			return false;
		} catch (IOException ex) {
			//Reconnect and continue download when download file have an error
//			System.out.println("Download file " + remoteFilePath + " failed");
			outputStream.close();
			downloadFile.delete(); //delete file downloaded error

			if(ftpClient.isConnected() == true){ //when connect is lost, auto reconnect
				System.out.println("Server is disconnect,	waitting for reconnect.....");
				Connect.reconnectToServer(Config.waitingTime);
				downloadDirectory(Connect.ftpClient, Config.remoteDirPath,
						"", Config.saveDirPath);
				return true;
			}else {
				return false;
			}
		} catch (Exception e) {
			System.out.println("Error..");
			downloadFile(ftpClient, remoteFilePath, savePath);
			
			e.printStackTrace();
			return false;
		}
		finally {
			if (outputStream != null) {
				outputStream.close();
			}
		}
	}
	
	//Create path of Directory base format on file Config
	public static void createNameOfDir(){
		Calendar cal = Calendar.getInstance();
		SimpleDateFormat sdf = new SimpleDateFormat(Config.formatClientDir);
		dir = sdf.format(cal.getTime()) + "/";
	}
	//Create Directory with path
	public static void createDirByName(String name){
		dirSaveName = name + File.separator + dir;
		File saveDirectory = new File(dirSaveName);
		if(!saveDirectory.exists()){
			if(saveDirectory.mkdirs()){
				System.out.println("Create Dir success: " + name + "/" + dir );
			} else {
				System.out.println("Create Dir failed: " + name + "/" + dir);
			}
		}
	}
	
	//redownload when file error
	public static boolean redownload(FTPClient ftpClient, String remoteFilePath, String savePath, final int timeToReconnect) throws FileNotFoundException{
		try {
			Thread.sleep(timeToReconnect);
			downloadFile(ftpClient, remoteFilePath, savePath);
			return true;
		} catch (Exception e) {
			return false;
		}
	}
}